package com.bright.ghj.overt.service.impl;

import com.bright.ghj.common.pojo.vo.PageVO;
import com.bright.ghj.common.util.CollectionUtil;
import com.bright.ghj.common.util.StringUtil;
import com.bright.ghj.overt.converter.PublicInfoMasterTableConverter;
import com.bright.ghj.overt.manager.DistZtManager;
import com.bright.ghj.overt.manager.FileListDFLZManager;
import com.bright.ghj.overt.manager.PublicInfoMasterTableManager;
import com.bright.ghj.overt.pojo.command.CollectPlatformCommand;
import com.bright.ghj.overt.pojo.dto.PublicInfoMasterTableDTO;
import com.bright.ghj.overt.pojo.dto.ZtDTO;
import com.bright.ghj.overt.pojo.po.primary.FileListDFLZ;
import com.bright.ghj.overt.pojo.query.OpenReportRecordQuery;
import com.bright.ghj.overt.pojo.vo.*;
import com.bright.ghj.overt.service.AsyncMessageService;
import com.bright.ghj.overt.service.BaseDataService;
import com.bright.ghj.overt.service.CollectPlatformService;
import com.bright.ghj.overt.task.timely.AsyncCollectPlatformExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static com.bright.ghj.overt.constant.PublicConstant.LIST_TYPE_EDIT;
import static com.bright.ghj.overt.enums.CollectPlatformStatus.ABANDON_EXECUTION;
import static com.bright.ghj.overt.enums.CollectPlatformStatus.IN_PROGRESS;
import static com.bright.ghj.overt.enums.DataStatus.*;

/**
 * @author Tz
 * @date 2024/01/22 15:03
 * @Description 上传到廉政平台 实现类
 */
@Slf4j
@Service
public class CollectPlatformServiceImpl implements CollectPlatformService {

    @Resource
    private BaseDataService baseDataService;

    @Resource
    private AsyncMessageService asyncMessageService;

    @Resource
    private FileListDFLZManager fileListDFLZManager;

    @Resource
    private DistZtManager distZtManager;

    @Resource
    private JdbcTemplate jdbcTemplatePrimary;

    @Resource
    private JdbcTemplate jdbcTemplateSecond;

    @Resource
    private PlatformTransactionManager transactionManagerPrimary;

    /**
     * 这里不能使用构造方法的注入方式 不知为何都是主数据源的事务管理器
     */
    @Resource
    private PlatformTransactionManager transactionManagerSecond;

    @Resource
    private PublicInfoMasterTableManager publicInfoMasterTableManager;

    @Resource
    private PublicInfoMasterTableConverter publicInfoMasterTableConverter;

    @Resource
    private RestTemplate restTemplate;

    /**
     * 上传到廉政平台的远端地址
     */
    @Value("${cwgk.collect.url}")
    private String collectDataUrl;

    /**
     * 当前地区标识
     */
    @Value("${cwgk.region}")
    private String region;

    /**
     * 收集数据到廉政平台
     * @param collectPlatformCommand 执行参数
     * @return                       返回结果消息列表
     */
    @Override
    public List<CollectPlatformAsyncTaskVO> collectToGovernment(CollectPlatformCommand collectPlatformCommand) {
        List<String> ztIds = collectPlatformCommand.getZtIds();
        String username = collectPlatformCommand.getUsername();
        Integer years = collectPlatformCommand.getYears();
        Integer months = collectPlatformCommand.getMonths();

        List<CollectPlatformAsyncTaskVO> collectPlatformAsyncTaskVOS = new ArrayList<>();

        //1. 查询账套
        List<ZtDTO> ztByZtIds = distZtManager.findByZtIds(ztIds);
        for (ZtDTO ztByZtId : ztByZtIds) {

            CollectPlatformAsyncTaskVO collectPlatformAsyncTaskVO = new CollectPlatformAsyncTaskVO();
            collectPlatformAsyncTaskVO.setIsSubmitTask(false);

            //查询当前账套需要上传到廉政平台的公开表
            List<FileListDFLZ> fileListDFLZS
                    = fileListDFLZManager.findCollectToGovernmentTableByZtTypeId(ztByZtId.getZtTypeId());

            //只需要校验需要上传的表是已审核的状态即可
            if (CollectionUtil.isEmpty(fileListDFLZS)) {
                collectPlatformAsyncTaskVO.setZtId(ztByZtId.getZtId());
                collectPlatformAsyncTaskVO.setZtName(ztByZtId.getZtName());
                collectPlatformAsyncTaskVO.setStatus(ABANDON_EXECUTION.getMessage());
                collectPlatformAsyncTaskVO.setRemark("该账套没有需要上传到廉政平台的报表");
                collectPlatformAsyncTaskVOS.add(collectPlatformAsyncTaskVO);
                continue;
            }

            OpenReportRecordQuery openReportRecordQuery = new OpenReportRecordQuery();
            openReportRecordQuery.setDistNo(ztByZtId.getDistNo());
            openReportRecordQuery.setYears(years);
            openReportRecordQuery.setMonths(months);
            openReportRecordQuery.setZtId(ztByZtId.getZtId());
            openReportRecordQuery.setPageNumber(1);
            openReportRecordQuery.setPageSize(Integer.MAX_VALUE);
            openReportRecordQuery.setZtId(ztByZtId.getZtId());

            //获取所有需要公开的公开表
            PageVO<OpenReportRecordVO> openReportRecordVO
                    = baseDataService.listOpenReportRecordByPage(openReportRecordQuery, LIST_TYPE_EDIT);
            List<OpenReportRecordVO> allData = openReportRecordVO.getData();

            //筛选出审核的公开表
            List<OpenReportRecordVO> auditedData = allData.stream()
                    .filter(e -> e.getStatus() != null && (e.getStatus().equals(AUDIT_SUCCESS_AND_READY_PUBLISH.getStatus())
                            || e.getStatus().equals(PUBLISHED_AND_READY_CITY_UPLOAD.getStatus())
                            || e.getStatus().equals(PUBLISHED.getStatus())))
                    .collect(Collectors.toList());

            //筛选出未审核的公开表
            List<OpenReportRecordVO> unauditedData = allData.stream()
                    .filter(e -> e.getStatus() == null || (!e.getStatus().equals(AUDIT_SUCCESS_AND_READY_PUBLISH.getStatus())
                            && !e.getStatus().equals(PUBLISHED_AND_READY_CITY_UPLOAD.getStatus())
                            && !e.getStatus().equals(PUBLISHED.getStatus())))
                    .collect(Collectors.toList());

            //1.1. 对账套的所有表进行校验 有不通过审核的则操作取消
            //只需要校验需要上传的表是已审核的状态即可
            if (CollectionUtil.isEmpty(auditedData)) {
                collectPlatformAsyncTaskVO.setZtId(ztByZtId.getZtId());
                collectPlatformAsyncTaskVO.setZtName(ztByZtId.getZtName());
                collectPlatformAsyncTaskVO.setStatus(ABANDON_EXECUTION.getMessage());
                collectPlatformAsyncTaskVO.setRemark("该账套所有报表均未审核");
                collectPlatformAsyncTaskVOS.add(collectPlatformAsyncTaskVO);
                continue;
            }


            //如果有值则存在校验不通过的表
            List<CollectPlatformAsyncTaskVO> checkTableAuditStatus = checkTableAuditStatus(ztByZtId, fileListDFLZS, unauditedData);
            if (!CollectionUtil.isEmpty(checkTableAuditStatus)) {
                collectPlatformAsyncTaskVOS.addAll(checkTableAuditStatus);
                continue;
            }


            //申请一个keyword
            String keyword = getKeyword(username);

            //1.2. 校验通过生成一个记录信息，可以让用户实时感知到上传的情况
            //1.3. 异步执行任务、监控该任务执行的状态和进度、 还要能够查看实际的采集情况
            AsyncCollectPlatformExecutor asyncTaskDTO = new AsyncCollectPlatformExecutor();
            asyncTaskDTO.setKeyword(keyword);
            asyncTaskDTO.setTaskType("上传廉政平台");
            asyncTaskDTO.setUsername(username);
            asyncTaskDTO.setYears(years);
            asyncTaskDTO.setMonths(months);
            asyncTaskDTO.setDistNo(ztByZtId.getDistNo());
            asyncTaskDTO.setDistName(ztByZtId.getDistName());
            asyncTaskDTO.setZtId(ztByZtId.getZtId());
            asyncTaskDTO.setZtName(ztByZtId.getZtName());
            asyncTaskDTO.setTaskName("上传廉政平台");

            //设置任务的事务管理器
            asyncTaskDTO.setTransactionManagerPrimary(transactionManagerPrimary);
            asyncTaskDTO.setTransactionManagerSecond(transactionManagerSecond);

            //设置数据库操作工具
            asyncTaskDTO.setJdbcTemplatePrimary(jdbcTemplatePrimary);
            asyncTaskDTO.setJdbcTemplateSecond(jdbcTemplateSecond);

            asyncTaskDTO.setPublicInfoMasterTableManager(publicInfoMasterTableManager);

            asyncTaskDTO.setFileListDFLZList(fileListDFLZS);
            asyncTaskDTO.setZtDTO(ztByZtId);

            asyncTaskDTO.setAuditedData(auditedData);

            /**
             * 同步锁的标识值 这里任务根据ztid+年份+月份来锁
             */
            asyncTaskDTO.setSyncKeyword(ztByZtId.getZtId() + "_" + years + "_" + months);

            //网络请求工具
            asyncTaskDTO.setRestTemplate(restTemplate);

            //请求接口地址
            asyncTaskDTO.setCollectDataUrl(collectDataUrl);

            //地区
            asyncTaskDTO.setRegion(region);

            //开始异步执行任务
            collectPlatformAsyncTaskVO.setKeyword(keyword);
            collectPlatformAsyncTaskVO.setZtId(ztByZtId.getZtId());
            collectPlatformAsyncTaskVO.setZtName(ztByZtId.getZtName());

            AsyncTaskResultVO asyncTaskResultVO = asyncMessageService.execAsyncTask(asyncTaskDTO);
            //如果任务成功提交
            if (asyncTaskResultVO != null && asyncTaskResultVO.getIsSubmitTask()) {
                collectPlatformAsyncTaskVO.setStatus(IN_PROGRESS.getMessage());
                collectPlatformAsyncTaskVO.setIsSubmitTask(asyncTaskResultVO.getIsSubmitTask());
                collectPlatformAsyncTaskVO.setRemark("任务执行中。。。");
            } else {
                collectPlatformAsyncTaskVO.setStatus(ABANDON_EXECUTION.getMessage());
                collectPlatformAsyncTaskVO.setRemark("执行失败");
                collectPlatformAsyncTaskVO.setNoSubmitIllustrate(asyncTaskResultVO != null ? asyncTaskResultVO.getNoSubmitIllustrate() : null);
            }
            collectPlatformAsyncTaskVOS.add(collectPlatformAsyncTaskVO);
        }
        return collectPlatformAsyncTaskVOS;
    }

    /**
     * 根据异步消息的keyword查询上传到廉政平台的情况
     *
     * @param keyword 异步任务的keyword
     * @return 返回上传的结果
     */
    @Override
    public List<PublicInfoMasterTableVO> getCollectInfo(String keyword) {
        List<AsyncMessageVO> asyncMessageVOS = asyncMessageService.listAsyncMessageByKeywords(Collections.singletonList(keyword));
        if (!CollectionUtil.isEmpty(asyncMessageVOS)) {
            AsyncMessageVO asyncMessageVO = asyncMessageVOS.get(0);

            if (!StringUtil.equals(asyncMessageVO.getTaskType(), "上传廉政平台")) {
                return null;
            }

            //根据年份、月份生成可能的公开表公开时间
            List<String> messageSendingTime = new ArrayList<>();

            //年表
            messageSendingTime.add(String.valueOf(asyncMessageVO.getYears()));


            //月表
            String collectionNumDate = asyncMessageVO.getYears() + "-";
            if (asyncMessageVO.getMonths() < 10) {
                collectionNumDate = collectionNumDate + "0";
            }
            collectionNumDate = collectionNumDate + asyncMessageVO.getMonths();
            messageSendingTime.add(collectionNumDate);


            //季度表
            collectionNumDate = asyncMessageVO.getYears() + "-";
            switch (asyncMessageVO.getMonths()) {
                case 1:
                case 2:
                case 3:
                    collectionNumDate = collectionNumDate + "A";
                    break;
                case 4:
                case 5:
                case 6:
                    collectionNumDate = collectionNumDate + "B";
                    break;
                case 7:
                case 8:
                case 9:
                    collectionNumDate = collectionNumDate + "C";
                    break;
                case 10:
                case 11:
                case 12:
                    collectionNumDate = collectionNumDate + "D";
                    break;
                default:
                    throw new IllegalStateException("Unexpected value: " + asyncMessageVO.getMonths());
            }
            messageSendingTime.add(collectionNumDate);

            //查询账套信息获取单位编码
            ZtDTO ztByZtIdByCache = distZtManager.getZtByZtIdByCache(asyncMessageVO.getZtId());

            //查询采集情况 根据公开表公开时间列表和单位编码
            List<PublicInfoMasterTableDTO> publicInfoMasterTableDTOS = publicInfoMasterTableManager.listPublicInfoMasterTable(messageSendingTime
                    , ztByZtIdByCache.getThreeDistNo());

            return publicInfoMasterTableConverter.dtoConvertVO(publicInfoMasterTableDTOS);
        }
        return null;
    }


    /**
     * 根据上传廉政的配置表，检查审核的状态， 未审核的公开表是否未在配置表中、是否需要跳过校验
     * @param ztDTO                 账套信息
     * @param listDFLZS             需要上传廉政报表的配置表
     * @param openReportRecordVOS   已审核的报表
     * @return                      检查结果列表
     */
    public List<CollectPlatformAsyncTaskVO> checkTableAuditStatus(ZtDTO ztDTO
            , List<FileListDFLZ> listDFLZS
            , List<OpenReportRecordVO> openReportRecordVOS) {

        List<CollectPlatformAsyncTaskVO> collectPlatformAsyncTaskVOS = new ArrayList<>();

        //获取需要上传廉政的公开报表名称列表
        List<String> openTableNames = openReportRecordVOS.stream()
                .map(e -> e.getTableName().trim())
                .distinct()
                .collect(Collectors.toList());

        // 根据FileListDFLZ 中的tableName去重
        listDFLZS = new ArrayList<>(listDFLZS.stream()
                .collect(Collectors.toMap(FileListDFLZ::getTableName, a -> a, (existing, replacement) -> existing))
                .values());

        List<String> errorTables = new ArrayList<>();
        for (FileListDFLZ listDFLZ : listDFLZS) {

            if (openTableNames.contains(listDFLZ.getTableName())) {
                //如果未审核的公开表 在需要上传的配置表中  表明未审核
                errorTables.add(String.format("报表：%s 未审核!", listDFLZ.getXmmc()));
            }
        }

        if (!CollectionUtil.isEmpty(errorTables)) {
            CollectPlatformAsyncTaskVO collectPlatformAsyncTaskVO = new CollectPlatformAsyncTaskVO();
            collectPlatformAsyncTaskVO.setZtId(ztDTO.getZtId());
            collectPlatformAsyncTaskVO.setZtName(ztDTO.getZtName());
            collectPlatformAsyncTaskVO.setStatus(ABANDON_EXECUTION.getMessage());
            collectPlatformAsyncTaskVO.setRemark("当前账套存在部分未审核公开表!");
            collectPlatformAsyncTaskVO.setErrorTables(errorTables);
            collectPlatformAsyncTaskVOS.add(collectPlatformAsyncTaskVO);
        }

        return collectPlatformAsyncTaskVOS;
    }


    /**
     * 获取一个唯一值 保证唯一
     * @param username  用户名
     * @return          唯一值，用作标识
     */
    public synchronized String getKeyword(String username) {
        return username + "_" + UUID.randomUUID();
    }
}
